package androidgame.framework.gl;

import javax.microedition.khronos.opengles.GL10;


import androidgame.framework.impl.GLGraphics;
import androidgame.framework.math.Vector2;

// Constructor sets the camera to the width and height specified. Then it sets the position of the camera
// to the center of the width and height. Modifying the Vector2 position modifies the location of the camera.
// setViewportAndMatrices() sets the projection matrix (aka where the camera is looking at) to the Vector2 position.
// touchToWorld converts the given touch coordinate to world coordinates.
// @author dicarlo2

public class Camera2D {
    public final Vector2 position;
    public float zoom;
    public final float frustumWidth;
    public final float frustumHeight;
    final GLGraphics glGraphics;
    
    public Camera2D(GLGraphics glGraphics, float frustumWidth, float frustumHeight) {
        this.glGraphics = glGraphics;
        this.frustumWidth = frustumWidth;
        this.frustumHeight = frustumHeight;
        this.position = new Vector2(frustumWidth / 2, frustumHeight / 2);
        this.zoom = 1.0f;
    }
    
    public void setViewportAndMatrices() {
        GL10 gl = glGraphics.getGL();
        gl.glViewport(0, 0, glGraphics.getWidth(), glGraphics.getHeight());
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(position.x - frustumWidth * zoom / 2, 
                    position.x + frustumWidth * zoom/ 2, 
                    position.y - frustumHeight * zoom / 2, 
                    position.y + frustumHeight * zoom/ 2, 
                    1, -1);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }
    
    public void touchToWorld(Vector2 touch) {
        touch.x = (touch.x / (float) glGraphics.getWidth()) * frustumWidth * zoom;
        touch.y = (1 - touch.y / (float) glGraphics.getHeight()) * frustumHeight * zoom;
        touch.add(position).sub(frustumWidth * zoom / 2, frustumHeight * zoom / 2);
    }
    
    public void distanceInWorld(Vector2 distance) {
    	distance.x = (distance.x / (float) glGraphics.getWidth()) * frustumWidth * zoom;
    	distance.y = -((distance.y / (float) glGraphics.getHeight()) * frustumHeight * zoom);
    }
    
    public void ensureWithinScene(float sceneWidth, float sceneHeight, float offsetWidth, float offsetHeight){
    	if (sceneWidth + offsetWidth < frustumWidth * zoom)
    		zoom = (sceneWidth + offsetWidth * 2) / frustumWidth;
    	if (sceneHeight + offsetHeight < frustumHeight * zoom)
    		zoom = (sceneHeight + offsetHeight * 2) / frustumHeight;
		if (position.x - frustumWidth * zoom / 2 < 0 - offsetWidth)
			position.x = frustumWidth / 2 * zoom - offsetWidth;
		else if (position.x > sceneWidth + offsetWidth - frustumWidth * zoom / 2)
			position.x = sceneWidth + offsetWidth - frustumWidth / 2 * zoom;
		if (position.y - frustumHeight * zoom / 2 < 0 - offsetHeight)
			position.y = frustumHeight / 2 * zoom - offsetHeight;
		else if (position.y > sceneHeight + offsetHeight - frustumHeight * zoom / 2)
			position.y = sceneHeight + offsetHeight - frustumHeight / 2 * zoom;
    }
}
